package service

import (
	"ant-agent/exec/model"
	"ant-agent/pkg/global"
	"ant-agent/pkg/logger"
	"encoding/json"
	"fmt"
	"os"
	"strings"
	"time"
)

func ExecJob(job *model.JobTask) error {
	// 创建执行模版
	if err := CreateJobExecutionTemplate(job); err != nil {
		logger.Error("创建任务执行模版失败: %s", err.Error())
		return err
	}

	// 初始化任务状态
	taskStatus := &TaskStatus{
		JobId:          job.Job.JobId,
		ExecCode:       job.Job.ExecCode,
		JobStatus:      job.Job.JobStatus,
		CurrentStep:    0,
		Tag:            job.Job.Tag,
		UsageType:      job.Job.UsageType,
		IP:             strings.Split(global.HttpAddr, ":")[0],
		SubJobs:        make(map[int]*model.SubJob),
		InputParams:    job.InputParams,
		OutputParams:   job.OutputParams,
		CancelChan:     make(chan bool, 10),
		ManualStepChan: make(chan model.TaskResumeRequest, 10),
	}
	for _, sj := range job.SubJobs {
		subJob := sj
		taskStatus.SubJobs[sj.StepNum] = &subJob
	}

	TaskManager.Lock()
	TaskManager.Tasks[job.Job.JobId] = taskStatus
	TaskManager.Unlock()

	// 启动异步执行
	go executeJobWithRetry(job, taskStatus, 1)
	return nil
}

// RetryJob 重试任务
func RetryJob(retryReq *model.TaskRetryRequest) error {
	logger.Debug("开始重试任务: 原JobId=%s, 新JobId=%s, 从步骤: %d 开始", retryReq.JobId, retryReq.NewJobId, retryReq.StepNum)
	// 1. 从结果文件中读取任务信息
	resultPath := fmt.Sprintf("%s/jobId_%s/result.json", JobsBaseDir, retryReq.JobId)
	data, err := os.ReadFile(resultPath)
	if err != nil {
		return fmt.Errorf("读取任务结果文件失败: %s", err.Error())
	}

	// 2. 解析任务信息
	var taskStatus TaskStatus
	if err := json.Unmarshal(data, &taskStatus); err != nil {
		return fmt.Errorf("解析任务结果文件失败: %s", err.Error())
	}

	// 3. 检查任务状态是否可以重试
	if taskStatus.JobStatus == model.JobRunning || taskStatus.JobStatus == model.JobProcessing {
		return fmt.Errorf("任务 %s 正在执行中，无法重试", retryReq.JobId)
	}

	// 4. 构建新的任务对象
	jobTask := &model.JobTask{
		Job: model.Job{
			JobId:         retryReq.NewJobId,
			ExecCode:      model.JobNotRunCode,
			JobStatus:     model.JobNotRun,
			Tag:           taskStatus.Tag,
			IP:            taskStatus.IP,
			OperationType: taskStatus.OperationType,
			JobType:       model.JobTypeManual,
			UsageType:     taskStatus.UsageType,
		},
		InputParams:  taskStatus.InputParams,
		OutputParams: taskStatus.OutputParams,
		SubJobs:      make([]model.SubJob, 0, len(taskStatus.SubJobs)),
	}

	// 5. 重置子任务状态
	for i := 1; i <= len(taskStatus.SubJobs); i++ {
		subJob := *taskStatus.SubJobs[i]
		// 根据重试模式重置状态
		if retryReq.StepNum == 0 || i >= retryReq.StepNum {
			// 需要重试的步骤，重置状态
			subJob.SubJobStatus = model.SubJobNotRun
			subJob.StartTime = 0
			subJob.EndTime = 0
			subJob.Result = json.RawMessage("{}")
		} else if !retryReq.ReuseEnv {
			// 对于不需要重试但不复用环境的步骤，也重置状态
			subJob.SubJobStatus = model.SubJobNotRun
			subJob.StartTime = 0
			subJob.EndTime = 0
			subJob.Result = json.RawMessage("{}")
		}
		jobTask.SubJobs = append(jobTask.SubJobs, subJob)
	}

	// 6. 创建新的执行状态
	newTaskStatus := &TaskStatus{
		JobId:          retryReq.NewJobId,
		ExecCode:       model.JobNotRunCode,
		JobStatus:      model.JobNotRun,
		CurrentStep:    0,
		Tag:            taskStatus.Tag,
		UsageType:      taskStatus.UsageType,
		IP:             taskStatus.IP,
		SubJobs:        make(map[int]*model.SubJob),
		InputParams:    taskStatus.InputParams,
		OutputParams:   taskStatus.OutputParams,
		CancelChan:     make(chan bool, 10),
		ManualStepChan: make(chan model.TaskResumeRequest, 10),
	}

	for _, sj := range jobTask.SubJobs {
		subJob := sj
		newTaskStatus.SubJobs[sj.StepNum] = &subJob
	}

	// 7. 将新状态添加到任务管理器
	TaskManager.Lock()
	TaskManager.Tasks[retryReq.NewJobId] = newTaskStatus
	TaskManager.Unlock()

	// 8. 重新创建执行模板
	if err := CreateJobExecutionTemplate(jobTask); err != nil {
		return fmt.Errorf("创建任务执行模板失败: %s", err.Error())
	}

	// 9. 启动异步执行
	go executeJobWithRetry(jobTask, newTaskStatus, retryReq.StepNum)

	logger.Debug("任务重试请求已处理: 原JobId=%s, 新JobId=%s", retryReq.JobId, retryReq.NewJobId)
	return nil
}

func CreateJobExecutionTemplate(job *model.JobTask) error {
	// 创建脚本文件
	scripts := job.SubJobs
	for _, script := range scripts {
		if script.StepType == model.StepTypeExecTask {
			suffix, err := getScriptSuffix(script.ScriptType)
			if err != nil {
				logger.Error("传入脚本类型为 %s, 获取脚本类型失败: %s", script.ScriptType, err.Error())
				return err
			}
			_, err = createScriptFile(job.Job.Tag, script.ScriptId, suffix, script.ScriptContent)
			if err != nil {
				logger.Error("创建脚本失败: %s", err.Error())
				return err
			}
		}
	}

	resultFilePath, err := createJobResultPath(job.Job.JobId)
	if err != nil {
		logger.Error("创建任务结果存储路径失败: %s", err.Error())
		return err
	}
	if err := writeResultToFile(resultFilePath, job); err != nil {
		logger.Error("写入结果文件失败: %s", err.Error())
		return err
	}
	logger.Debug("创建任务执行模板成功")
	return nil
}

// 父作业执行逻辑
func executeJobWithRetry(job *model.JobTask, taskStatus *TaskStatus, startStep int) {
	TaskManager.Lock()
	taskStatus.ExecCode = model.JobRunningCode
	taskStatus.JobStatus = model.JobRunning
	TaskManager.Unlock()

	// 从指定步骤开始执行
	startIdx := 0
	if startStep > 0 {
		// 找到对应的步骤索引
		for i, sj := range job.SubJobs {
			if sj.StepNum == startStep {
				startIdx = i
				break
			}
		}
	}

	for i, subJob := range job.SubJobs {
		// 跳过指定开始步骤之前的任务
		if i < startIdx {
			continue
		}
		// 检查依赖
		if len(subJob.Dependencies) > 0 {
			for _, depStepNum := range subJob.Dependencies {
				for {
					TaskManager.RLock()
					depStatus := taskStatus.SubJobs[depStepNum].SubJobStatus
					TaskManager.RUnlock()
					if depStatus == model.JobSuccess {
						break
					}
					if depStatus != model.JobSuccess {
						TaskManager.Lock()
						taskStatus.ExecCode = model.GetJobCodeByStatus(depStatus)
						taskStatus.JobStatus = depStatus
						TaskManager.Unlock()
						logger.Error("任务终止: jobId=%s 原因: 依赖步骤 step=%d 执行失败", job.Job.JobId, depStepNum)
						return
					}
					time.Sleep(1 * time.Second)
				}
			}
		}

		// 切换执行步骤
		TaskManager.Lock()
		subStatus := taskStatus.SubJobs[subJob.StepNum]
		taskStatus.CurrentStep = subJob.StepNum
		TaskManager.Unlock()

		// 根据StepType调用相应的处理函数
		var success bool
		var err error

		switch subJob.StepType {
		case model.StepTypeManualReview:
			success, err = executeManualStep(job.Job.JobId, subJob.StepNum, subStatus, taskStatus)
		case model.StepTypeExecTask:
			success, err = executeTaskStep(job.Job.JobId, subJob.ScriptId, subStatus, taskStatus)
		case model.StepTypeProcessControl:
			// 流程控制类型可以在这里添加处理逻辑
			logger.Info("任务 jobId=%s 步骤 step=%d 流程控制类型, 跳过执行", job.Job.JobId, subJob.StepNum)
			success = true
		default:
			logger.Warn("任务 jobId=%s 步骤 step=%d 未知类型: %s, 跳过执行", job.Job.JobId, subJob.StepNum, subJob.StepType)
			success = true
		}

		if !success {
			logger.Error("任务 jobId=%s 步骤 step=%d 执行失败: %v", job.Job.JobId, subJob.StepNum, err)
			return
		}
	}

	// 所有子任务成功
	TaskManager.Lock()
	taskStatus.ExecCode = model.JobSuccessCode
	taskStatus.JobStatus = model.JobSuccess
	TaskManager.Unlock()

	cleanupTaskStatus(job.Job.JobId, model.JobSuccessCode)
	writeResultToFile(fmt.Sprintf("%s/jobId_%s/result.json", JobsBaseDir, job.Job.JobId), taskStatus)
	logger.Info("任务执行完成: jobId=%s, 执行结果文件: %s", job.Job.JobId, fmt.Sprintf("%s/jobId_%s/result.json", JobsBaseDir, job.Job.JobId))
}

// 执行脚本
func executeScript(jobId, tag, scriptId string, subJob *model.SubJob) error {
	TaskManager.Lock()
	subJob.SubJobStatus = model.SubJobRunning
	subJob.StartTime = time.Now().UnixMilli()
	TaskManager.Unlock()

	scriptResultPath, err := createScriptResultPath(jobId, scriptId)
	if err != nil {
		return err
	}

	scriptPath, err := getScriptFilePath(tag, subJob.ScriptId)
	if err != nil {
		return err
	}

	interpreter, err := getScriptInterpreter(scriptPath)
	if err != nil {
		return err
	}

	var scriptParam string
	TaskManager.RLock()
	for _, input := range TaskManager.Tasks[subJob.JobId].InputParams {
		if input.Name == subJob.ScriptParam {
			scriptParam = string(input.Value)
		}
	}
	TaskManager.RUnlock()

	cancelChan := make(chan bool)
	logger.Debug("子任务 %d 执行参数: %s %s", subJob.StepNum, subJob.ScriptParam, scriptParam)
	stdout, stderr, statusMessage, exitCode, err := runScriptWithCancel(interpreter, scriptPath, scriptParam, subJob.ScriptTimeout, cancelChan)
	logger.Debug("子任务 %d 执行结果: exit=%d, stdout=%s, stderr=%s", subJob.StepNum, exitCode, stdout, stderr)
	result := &model.CmdResult{
		Stdout:  stdout,
		Stderr:  stderr,
		RetCode: exitCode,
		Message: statusMessage,
	}

	TaskManager.Lock()
	if b, merr := json.Marshal(result); merr == nil {
		subJob.Result = json.RawMessage(b)
	} else {
		subJob.Result = json.RawMessage([]byte("{}"))
	}
	subJob.SubJobStatus = statusMessage
	subJob.EndTime = time.Now().UnixMilli()
	TaskManager.Unlock()

	writeResultToFile(scriptResultPath, subJob)
	return err
}

func cleanupTaskStatus(jobId string, jobStatusCode string) {
	if jobStatusCode == model.JobSuccessCode {
		TaskManager.Lock()
		delete(TaskManager.Tasks, jobId)
		TaskManager.Unlock()
		logger.Debug("任务执行成功，已从内存清理: jobId=%s", jobId)
	}
}

// 执行脚本任务步骤
func executeTaskStep(jobId, scriptId string, subStatus *model.SubJob, taskStatus *TaskStatus) (bool, error) {
	err := executeScript(jobId, taskStatus.Tag, scriptId, subStatus)

	TaskManager.Lock()
	if err != nil || subStatus.SubJobStatus != model.SubJobSuccess {
		taskStatus.ExecCode = model.GetJobCodeByStatus(subStatus.SubJobStatus)
		taskStatus.JobStatus = subStatus.SubJobStatus
		TaskManager.Unlock()
		logger.Error("子任务 %d 执行失败: %s", subStatus.StepNum, subStatus.SubJobStatus)
		writeResultToFile(fmt.Sprintf("%s/jobId_%s/result.json", JobsBaseDir, jobId), taskStatus)
		return false, fmt.Errorf("子任务执行失败: %s", err)
	}
	TaskManager.Unlock()

	return true, nil
}

// 执行人工处理步骤
func executeManualStep(jobId string, stepNum int, subStatus *model.SubJob, taskStatus *TaskStatus) (bool, error) {
	TaskManager.Lock()
	subStatus.SubJobStatus = model.SubJobProcessing
	subStatus.StartTime = time.Now().UnixMilli()
	taskStatus.ExecCode = model.JobProcessingCode
	taskStatus.JobStatus = model.JobProcessing
	TaskManager.Unlock()

	logger.Info("任务 %s 步骤 %d 进入人工处理状态，等待信号", jobId, stepNum)
	writeResultToFile(fmt.Sprintf("%s/jobId_%s/result.json", JobsBaseDir, jobId), taskStatus)

	select {
	case resumeReq := <-taskStatus.ManualStepChan:
		TaskManager.Lock()

		switch resumeReq.Action {
		case model.ResumeActionContinue:
			subStatus.SubJobStatus = model.ResumeActionContinue
			subStatus.EndTime = time.Now().UnixMilli()
			taskStatus.ExecCode = model.JobRunningCode
			taskStatus.JobStatus = model.JobRunning
			logger.Debug("任务 %s 步骤 %d 人工确认继续", jobId, stepNum)
			TaskManager.Unlock()
			return true, nil
		case model.ResumeActionSkip:
			subStatus.SubJobStatus = model.ResumeActionSkip
			subStatus.EndTime = time.Now().UnixMilli()
			taskStatus.ExecCode = model.JobRunningCode
			taskStatus.JobStatus = model.JobRunning
			logger.Debug("任务 %s 步骤 %d 已跳过", jobId, stepNum)
			TaskManager.Unlock()
			return true, nil
		case model.ResumeActionCancel:
			subStatus.SubJobStatus = model.SubJobCanceled
			subStatus.EndTime = time.Now().UnixMilli()
			taskStatus.ExecCode = model.JobCanceledCode
			taskStatus.JobStatus = model.JobCanceled
			logger.Debug("任务 %s 已取消", jobId)
			writeResultToFile(fmt.Sprintf("%s/jobId_%s/result.json", JobsBaseDir, jobId), taskStatus)
			TaskManager.Unlock()
			return false, fmt.Errorf("任务已取消")
		}
		TaskManager.Unlock()
		return false, fmt.Errorf("未知的恢复操作: %s", resumeReq.Action)
	case <-taskStatus.CancelChan:
		TaskManager.Lock()
		subStatus.SubJobStatus = model.SubJobCanceled
		subStatus.EndTime = time.Now().UnixMilli()
		taskStatus.ExecCode = model.JobCanceledCode
		taskStatus.JobStatus = model.JobCanceled
		TaskManager.Unlock()

		logger.Info("任务 %s 已被外部取消", jobId)
		writeResultToFile(fmt.Sprintf("%s/jobId_%s/result.json", JobsBaseDir, jobId), taskStatus)
		return false, fmt.Errorf("任务已被外部取消")
	}
}
